package org.ljy;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;

public class ZKLogExtractor {
    // -------------------------- 新增：所有角色变更的正则匹配规则 --------------------------
    // 1. 时间戳正则（通用，匹配 yyyy-MM-dd HH:mm:ss,SSS）
    private static final Pattern TIMESTAMP_PATTERN = Pattern.compile("^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3})");

    // 2. 选举通知日志：Notification: my state:XXX;（如LOOKING/FOLLOWING/LEADING）
    private static final Pattern NOTIFICATION_STATE_PATTERN = Pattern.compile("Notification: my state:([A-Z]+);");

    // 3. 纯角色切换日志：Peer state changed: XXX（如following → 转为FOLLOWING）
    private static final Pattern PEER_SIMPLE_STATE_PATTERN = Pattern.compile("Peer state changed: ([a-z]+)");

    // 4. 角色+阶段变更日志：Peer state changed: following - XXX（如following-discovery）
    private static final Pattern PEER_STAGE_STATE_PATTERN = Pattern.compile("Peer state changed: (following - [a-z]+)");

    // 5. 显式角色日志：QuorumPeer@1465] - XXX（如FOLLOWING/LOOKING，纯大写）
    private static final Pattern EXPLICIT_ROLE_PATTERN = Pattern.compile("QuorumPeer@1465\\] - ([A-Z]+)");

    // -------------------------- 核心方法：提取所有角色变更日志 --------------------------
    public static Map<String, String> extractStateMap(String logFilePath) throws IOException {
        Map<String, String> stateMap = new HashMap<>();
        File logFile = new File(logFilePath);
        if (!logFile.exists()) {
            throw new IllegalArgumentException("日志文件不存在：" + logFilePath);
        }

        String lastState = null; // 用于去重：保存上一条记录的状态
        // 遍历每一行日志，逐一匹配所有角色变更规则
        for (String logLine : FileUtils.readLines(logFile, "UTF-8")) {
            String timestamp = extractTimestamp(logLine); // 提取时间戳（通用逻辑）
            String state = null; // 提取的角色/状态

            // 分支1：匹配选举通知日志（如Notification: my state:LOOKING;）
            if (logLine.contains("Notification: my state:")) {
                state = matchPattern(logLine, NOTIFICATION_STATE_PATTERN);
            }
            // 分支2：匹配角色+阶段变更日志（如Peer state changed: following - discovery）
            else if (logLine.contains("Peer state changed: following - ")) {
                state = matchPattern(logLine, PEER_STAGE_STATE_PATTERN);
            }
            // 分支3：匹配纯角色切换日志（如Peer state changed: following）
            else if (logLine.contains("Peer state changed: ")) {
                state = matchPattern(logLine, PEER_SIMPLE_STATE_PATTERN);
                if (state != null) {
                    state = state.toUpperCase(); // 转为大写（如following → FOLLOWING）
                }
            }
            // 分支4：匹配显式角色日志（如QuorumPeer@1465] - FOLLOWING）
            else if (logLine.contains("QuorumPeer@1465] - ")) {
                state = matchPattern(logLine, EXPLICIT_ROLE_PATTERN);
            }

            // 去重逻辑：仅当时间戳、状态非空，且与上一条状态不同时记录
            if (timestamp != null && state != null) {
                if (lastState == null || !state.equals(lastState)) {
                    String key = timestamp;
                    String value = "C1ZK4:" + state; // 服务器标识固定为C1ZK4（可动态提取）
                    stateMap.put(key, value);
                    lastState = state; // 更新上一条状态，用于下一轮去重
                    System.out.printf("提取成功：%s -> %s%n", key, value);
                }
            }
        }
        return stateMap;
    }

    // -------------------------- 工具方法：提取时间戳 + 正则匹配 --------------------------
    /**
     * 提取日志行的时间戳
     */
    private static String extractTimestamp(String logLine) {
        Matcher matcher = TIMESTAMP_PATTERN.matcher(logLine);
        return matcher.find() ? matcher.group(1) : null;
    }

    /**
     * 通用正则匹配方法：传入日志行和Pattern，返回匹配到的结果（第一组）
     */
    private static String matchPattern(String logLine, Pattern pattern) {
        Matcher matcher = pattern.matcher(logLine);
        return matcher.find() ? matcher.group(1) : null;
    }

    // -------------------------- 测试方法 --------------------------
    public static void main(String[] args) {
        // 日志文件路径（替换为你的实际.out日志路径）
        String logPath = "./src/main/java/org/ljy/zookeeper--server-C1ZK4.out";
        try {
            Map<String, String> resultMap = extractStateMap(logPath);
            // 输出最终去重后的角色变更记录
            System.out.println("\n最终提取的角色变更Map（去重后）：");
            resultMap.forEach((k, v) -> System.out.printf("%s -> %s%n", k, v));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
